﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using MLRobotic.Tower.Common;
using System.Drawing;
using System.Drawing.Imaging;

namespace MLRobotic.Tower.Detection
{
    public class TargetColor
    {
        public TargetColor(Color display, PixelFormat pixelFormat)
            : this(display, 0, 10, 1, 0.3, 1, 0.5, 0.3, 0.9, pixelFormat)
        {
        }

        public TargetColor(Color display, double hue, PixelFormat pixelFormat)
            : this(display, hue, 10, 1, 0.3, 1, 0.5, 0.3, 0.9, pixelFormat)
        {
        }

        public TargetColor(Color display, double hue, double deltaHue, 
            double saturation, double minSaturation, double maxSaturation,
            double brightness, double minBrightness, double maxBrightness,
            PixelFormat pixelFormat)
        {
            Display = display;

            Hue = hue;
            DeltaHue = deltaHue;

            Saturation = saturation;
            MinSaturation = minSaturation;
            MaxSaturation = maxSaturation;

            Brightness = brightness;
            MinBrightness = minBrightness;
            MaxBrightness = maxBrightness;

            Key = new byte[BitmapHelper.GetBytesPerPixel(pixelFormat)];
            BitmapHelper.SetPixel(display, Key, 0, pixelFormat);
        }

        public Color Display { get; private set; }
        public byte[] Key { get; private set; }

        #region Hue

        private double _hue;
        public double Hue
        {
            get
            { 
                return _hue;
            } 
            set 
            {
                if (value > 360)
                    value = 360;

                if (value < 0)
                    value = 0;

                _hue = value;

                UpdateHueIntervals();
            }
        }

        private double _deltaHue;
        public double DeltaHue
        {
            get
            {
                return _deltaHue;
            }
            set
            {
                if (value > 180)
                    value = 180;

                if (value < 0)
                    value = 0;

                _deltaHue = value;

                UpdateHueIntervals();
            }
        }

        public double MinHue { get; private set; }

        public double MaxHue { get; private set; }

        private void UpdateHueIntervals()
        {
            var min = _hue - _deltaHue;
            var max = _hue + _deltaHue;

            MinHue = min < 0 ? min + 360 : min;
            MaxHue = max > 360 ? max - 360 : max;
        }
        #endregion

        #region Saturation

        private double _saturation;
        public double Saturation
        {
            get
            {
                return _saturation;
            }
            set
            {
                _saturation = value;
            }
        }

        private double _minSaturation;
        public double MinSaturation
        {
            get
            {
                return _minSaturation;
            }
            set
            {
                if (value > 1)
                    value = 1;

                if (value < 0)
                    value = 0;

                _minSaturation = value;
            }
        }

        private double _maxSaturation;
        public double MaxSaturation
        {
            get
            {
                return _maxSaturation;
            }
            set
            {
                if (value > 1)
                    value = 1;

                if (value < 0)
                    value = 0;

                _maxSaturation = value;
            }
        }
        #endregion

        #region Brightness

        private double _brightness;
        public double Brightness
        {
            get
            {
                return _brightness;
            }
            set
            {
                _brightness = value;
            }
        }

        private double _minBrightness;
        public double MinBrightness
        {
            get
            {
                return _minBrightness;
            }
            set
            {
                if (value > 1)
                    value = 1;

                if (value < 0)
                    value = 0;

                _minBrightness = value;
            }
        }

        private double _maxBrightness;
        public double MaxBrightness
        {
            get
            {
                return _maxBrightness;
            }
            set
            {
                if (value > 1)
                    value = 1;

                if (value < 0)
                    value = 0;

                _maxBrightness = value;
            }
        }
        #endregion

        public void SetColor(Color color)
        {
            SetColor(color.R, color.G, color.B);
        }

        public void SetColor(byte r, byte g, byte b)
        {
            double h, s, v;
            HsvHelper.ColorToHSL(r, g, b, out h, out s, out v);
            Hue = h;
            Saturation = s;
            Brightness = v;
        }

        public bool Match(double hue, double saturation, double brightness)
        {
            return ( (MinHue < MaxHue && hue >= MinHue && hue <= MaxHue) 
                    || (MinHue > MaxHue && (hue >= MinHue || hue <= MaxHue))
                    || (MinHue == MaxHue && _deltaHue == 180) )
                && saturation >= _minSaturation && saturation <= _maxSaturation
                && brightness >= _minBrightness && brightness <= _maxBrightness;
        }
    }
}
